package gdt.entity;

import gdt.entity.embeddable.Contact;
import gdt.entity.security.Authority;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.TimeZone;
import javax.persistence.*;

import org.hibernate.validator.NotEmpty;
import org.hibernate.validator.NotNull;
import org.hibernate.validator.Valid;
import org.springframework.security.GrantedAuthority;
import org.springframework.security.GrantedAuthorityImpl;
import org.springframework.security.userdetails.UserDetails;

import static javax.persistence.FetchType.LAZY;
import static javax.persistence.CascadeType.ALL;

/**
 * Entity that represents a member of the group.
 * It can be assigned holidays, projects and tasks.
 * It has associated an user to access the system.
 */

@Entity
public class Member extends AbstractSecureEntity implements Serializable, UserDetails {

	private static final long serialVersionUID = 1L;
	
	@Valid
	@Embedded
	private Contact contact = new Contact();
	
	private String photo = "default.jpg";
	
	@Column(name="position_")
	private String position;
	

	private int workDayLength;
	
	private TimeZone timezone = TimeZone.getDefault();
	
	@NotEmpty
	private String username;
	
	@NotEmpty
	private String password;
	
	private boolean enabled = true;
	
	private boolean accountNonExpired = true;

	private boolean accountNonLocked = true;

	private boolean credentialsNonExpired = true;

	
	@OneToMany(fetch = FetchType.EAGER, mappedBy="user", cascade = ALL)
	private List<Authority> authorities = new LinkedList<Authority>();
	
	@NotNull
	@ManyToOne(fetch=LAZY)
	private Group group;
	
	@ManyToMany(fetch=LAZY, mappedBy = "assignedMembers")
	private List<Project> assignedProjects = new LinkedList<Project>();
	
	@OneToMany(fetch=LAZY,mappedBy = "assignedMember")
	private List<Task> assignedTasks = new LinkedList<Task>();
	
	@OneToMany(fetch=LAZY, mappedBy = "assignedMember", cascade = ALL)
	private List<MemberHoliday> holidays = new LinkedList<MemberHoliday>();

	
	public Member() {
		super();
		this.setEnabled(true);
	}   
	
	// ********************** Accessor Methods ********************** //
	
	public Contact getContact() {
		return this.contact;
	}

	public void setContact(Contact contact) {
		this.contact = contact;
	}   
	public String getPhoto() {
		return this.photo;
	}

	public void setPhoto(String photo) {
		this.photo = photo;
	}   
	public String getPosition() {
		return this.position;
	}

	public void setPosition(String position) {
		this.position = position;
	}   
	public int getWorkDayLength() {
		return this.workDayLength;
	}

	public void setWorkDayLength(int workDayLength) {
		this.workDayLength = workDayLength;
	}   
	public TimeZone getTimezone() {
		return this.timezone;
	}

	public void setTimezone(TimeZone timezone) {
		this.timezone = timezone;
	}
	public void setUsername(String username) {
		this.username = username;
	}

	public String getUsername() {
		return username;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getPassword() {
		return password;
	}

	public void setEnabled(boolean enabled) {
		this.enabled = enabled;
	}

	public boolean isEnabled() {
		return enabled;
	}

	public void setAuthorities(List<Authority> authorities) {
		this.authorities = authorities;
	}

	public GrantedAuthority[] getAuthorities() {

		List<GrantedAuthorityImpl> list = new ArrayList<GrantedAuthorityImpl>();
		for (Authority auth : authorities)
			list.add(new GrantedAuthorityImpl(auth.getAuthority()));
		
		return (GrantedAuthority[])list.toArray(new GrantedAuthority[0]);
	}

	public void setAccountNonExpired(boolean accountNonExpired) {
		this.accountNonExpired = accountNonExpired;
	}

	public boolean isAccountNonExpired() {
		return accountNonExpired;
	}

	public void setAccountNonLocked(boolean accountNonLocked) {
		this.accountNonLocked = accountNonLocked;
	}

	public boolean isAccountNonLocked() {
		return accountNonLocked;
	}

	public void setCredentialsNonExpired(boolean credentialsNonExpired) {
		this.credentialsNonExpired = credentialsNonExpired;
	}

	public boolean isCredentialsNonExpired() {
		return credentialsNonExpired;
	}

	public void setGroup(Group group) {
		this.group = group;
	}
	public Group getGroup() {
		return group;
	}
	public void setAssignedProjects(List<Project> assignedProjects) {
		this.assignedProjects = assignedProjects;
	}
	public List<Project> getAssignedProjects() {
		return assignedProjects;
	}
	public void setAssignedTasks(List<Task> assignedTasks) {
		this.assignedTasks = assignedTasks;
	}
	public List<Task> getAssignedTasks() {
		return assignedTasks;
	}

	public void setHolidays(List<MemberHoliday> holidays) {
		this.holidays = holidays;
	}
	public List<MemberHoliday> getHolidays() {
		return holidays;
	}
	
	public void addAuthority(String role){
		Authority authority = null;
		for(Authority a : authorities)
			if(a.getAuthority().equals(role))
				authority = a;
		
		if(authority == null)
			authorities.add(new Authority(role,this));
	}
	
	public void removeAuthority(String role){
		Authority authority = null;
		for(Authority a : authorities)
			if(a.getAuthority().equals(role))
				authority = a;
		
		if(authority != null){
			authorities.remove(authority);
			authority.setUser(null);
		}
	}
	
	
	// *********************** Adder Methods *********************** //
	
	public void addProject(Project project){
		this.assignedProjects.add(project);
		project.getAssignedMembers().add(this);
	}
   
	public void addTask(Task task){
		this.assignedTasks.add(task);
		task.setAssignedMember(this);
	}

	
	// *********************** Remover Methods *********************** //
	
	public void removeProject(Project project){
		this.assignedProjects.remove(project);
	}
   
	public void removeTask(Task task){
		this.assignedTasks.remove(task);
	}
}
